package com.terrence.filemgr.mgr.impl.ftp;

import java.io.InputStream;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

import com.terrence.filemgr.FileMgrException;
import com.terrence.filemgr.mgr.FilePathGenerator;
import com.terrence.filemgr.mgr.vo.DirVo;

/**
 * 
 * @author wuchuang
 *
 * 2016年11月11日 下午4:59:35
 * 
 * FTP工具类
 */
public class FTPUtil {
	
	private FTPContext context = null;
	
	private FTPUtil(FTPContext context) {
		this.context = context;
	}
	
	public static FTPUtil getInstance(FTPContext context){
		return new FTPUtil(context);
	}

	/**
	 * 
	 * 连接
	 * @throws FTPException
	 */
	private FTPClient connect() throws FTPException {
		try{
			FTPClient ftpClient = new FTPClient();
			ftpClient.connect(context.getHostName(),context.getPort());
//			if(context.getIsPasv()){
//				ftpClient.enterLocalPassiveMode();
//			}else{
//				ftpClient.enterLocalActiveMode();
//			}
			ftpClient.setBufferSize(1024);
			ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
			ftpClient.setDefaultTimeout(1000*60*2);
			ftpClient.setControlEncoding(context.getEncoding());
			ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE); 
			ftpClient.login(context.getUserName(), context.getPassword());
			return ftpClient;
		}catch(Exception ex){
			throw new FTPException(ex);
		}
	}
	
	/**
	 * 
	 * 释放连接
	 */
	private void disconnect(FTPClient ftpClient){
		try{
			if(null!=ftpClient && ftpClient.isConnected()){
			    ftpClient.disconnect();
			}
		}catch(Exception ex){
			//异常不处理
		}
	}
	
	public String uploadFile(InputStream inputStream, String fileRelativeDir,String fileName) throws FTPException {
		FTPClient ftpClient = null;
		try{
            //处理目录
			String dirPath = context.getBaseDir()+context.getPathSeperator()+fileRelativeDir;
			this.createDir(dirPath);
			ftpClient = this.connect();
            ftpClient.changeWorkingDirectory(dirPath);
			ftpClient.storeFile(fileName, inputStream);
			return fileRelativeDir+context.getPathSeperator()+fileName;
		}catch(Exception ex){
			throw new FTPException(ex);
		}finally{
			this.disconnect(ftpClient);
		}
	}

	public String uploadFile(InputStream inputStream, String fileType) throws FTPException {
		FTPClient ftpClient = null;
		try{
            //处理目录
			String dirPath = FilePathGenerator.generateDirPath(context.getPathSeperator(), context.getBaseDir());
			String fileName = FilePathGenerator.generateFileName(fileType);
			this.createDir(dirPath);
			ftpClient = this.connect();
            ftpClient.changeWorkingDirectory(dirPath);
			ftpClient.storeFile(fileName, inputStream);
			return dirPath+context.getPathSeperator()+fileName;
		}catch(Exception ex){
			throw new FTPException(ex);
		}finally{
			this.disconnect(ftpClient);
		}
	}
	
	public InputStream download(String fileRelativePath) throws FTPException {
		FTPClient ftpClient = null;
		InputStream inputStream = null;
		try{
			ftpClient = this.connect();
			FTPFile[] files = ftpClient.listFiles(fileRelativePath);
			if (null!=files && files.length == 1) {
			   inputStream = ftpClient.retrieveFileStream(fileRelativePath);
			}
			return inputStream;
		}catch(Exception ex){
			throw new FTPException(ex);
		}finally{
			//inputStream流不能关闭，否则拿不到数据
			this.disconnect(ftpClient);
		}
	}

	/**
	 * 
	 * 删除文件
	 * @param path
	 * @throws FTPException
	 */
	public Boolean remove(String fileRelativePath) throws FTPException{
		Boolean isFinished = Boolean.TRUE;
		FTPClient ftpClient = null;
		try {
			ftpClient = this.connect();
			FTPFile[] files = ftpClient.listFiles(fileRelativePath);
			if(null!=files && files.length == 1){
				FTPFile file = files[0];
				if(file.isDirectory()){
					isFinished = isFinished && removeDir(ftpClient,fileRelativePath);
				}else if(file.isFile()){
					isFinished = isFinished && removeFile(ftpClient, fileRelativePath);
				}
			}
			return isFinished;
		} catch (Exception ex) {
			throw new FTPException(ex);
		} finally{
			this.disconnect(ftpClient);
		}
	}
	
	private boolean removeDir(FTPClient ftpClient,String dirPath) throws FTPException{
		Boolean isFinished = Boolean.TRUE;
		try{
			FTPFile[] files = ftpClient.listFiles(dirPath);
			if(null!=files){
				for(FTPFile file: files){
					if(file.isDirectory()){
						isFinished = isFinished && removeDir(ftpClient,dirPath+context.getPathSeperator()+file.getName());
						isFinished = isFinished && ftpClient.removeDirectory(dirPath);
					}else if(file.isFile()){
						isFinished = isFinished && removeFile(ftpClient,dirPath+context.getPathSeperator()+file.getName());
					}
				}
			}
			return isFinished;
		}catch(Exception ex){
			throw new FTPException(ex);
		}
	}
	/**
	 * 删除文件
	 * @param ftpClient
	 * @param filePath
	 * @return
	 * @throws FTPException
	 */
	private boolean removeFile(FTPClient ftpClient,String filePath) throws FTPException{
		try{
			return ftpClient.deleteFile(filePath);
		}catch(Exception ex){
			throw new FTPException(ex);
		}
	}
	
	public void createDir(String dirPath) throws FTPException {
		if(StringUtils.isEmpty(dirPath)){
			throw new FTPException("FTP目录路径不能为空!");
		}
		FTPClient ftpClient = null;
		try{
			ftpClient = this.connect();
			String[] paths = StringUtils.split(dirPath,context.getPathSeperator());
			if(paths.length == 0){
				//此路径为根路径，不需要创建
			}else{
				StringBuilder currentDir = new StringBuilder();
				for(int index = 0,length= paths.length;index<length;index++){
					currentDir.append(context.getPathSeperator());
					currentDir.append(paths[index]);
					ftpClient.makeDirectory(currentDir.toString());
				}
			}
		}catch(Exception ex){
			throw new FTPException(ex);
		}finally{
			this.disconnect(ftpClient);
		}
	}
	
	public Boolean isDirValid(String dirPath) throws FileMgrException {
		FTPClient ftpClient = null;
		try {
			ftpClient = this.connect();
			dirPath = (null == dirPath ? "" : dirPath);
			//将测试文件上传到指定目录
			String filePath = uploadFile(FTPUtil.class.getResourceAsStream("../check.file"), dirPath,"check.file");
			//删除测试文件
			removeFile(ftpClient, filePath);
			return Boolean.TRUE;
		} catch (Exception e) {
			return Boolean.FALSE;
		}
	}
	
	public DirVo getDirStructures(String relativePath) throws FileMgrException {
		FTPClient ftpClient = null;
		try {
			ftpClient = this.connect();
			String dirPath = context.getBaseDir() + (StringUtils.isNotBlank(relativePath) ? context.getPathSeperator()+relativePath : "");
			DirVo dirVo = new DirVo();
			dirVo.setName(dirPath);
			dirVo.setPath("");
			readDirstructures(ftpClient,dirVo);
			return dirVo;
		} catch (Exception e) {
			throw new FileMgrException(e);
		}
	}

	private void readDirstructures(FTPClient ftpClient,DirVo parentDir) throws FileMgrException {
		try {
			FTPFile[] files = ftpClient.listFiles(context.getBaseDir()+context.getPathSeperator()+parentDir.getPath());
			for(FTPFile file : files){
				if(file.isDirectory()){
					DirVo dirVo = new DirVo();
					dirVo.setName(file.getName());
					dirVo.setPath(parentDir.getPath()+context.getPathSeperator()+file.getName());
					parentDir.addSubDir(dirVo);
					
					readDirstructures(ftpClient, dirVo);
				}
			}
		} catch (Exception e) {
			throw new FileMgrException(e);
		}
	}
	
//	public static void main(String[] args){
//		FTPContext context = new FTPContext();
//		context.setHostName("14.215.114.49");
//		context.setPort(21);
//		context.setUserName("ftpuser");
//		context.setPassword("ftppassword");
//		context.setIsUnix(Boolean.TRUE);
//		context.setIsPasv(Boolean.TRUE);
//		context.setEncoding("UTF-8");
//		context.setBaseDir("dataPlatform");
//		FTPUtil ftp = FTPUtil.getInstance(context);
//		
//		try{
////			File file = new File("D:\\test.txt");
////			ftp.uploadFile(file, "test");
//			//ftp.list("/20160506");
//			//ftp.download("/dataPlatform/2016/11/test.txt");
//			//ftp.remove("/dataPlatform/2016/11/test.txt");
//			//ftp.remove("/dataPlatform");
//			 int buffered=2048;
//			   BufferedInputStream bis=new BufferedInputStream(ftp.download("/dataPlatform/2016/11/test.txt"),buffered);
//			   BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\kkk.txt"));
//			   final byte[] bytes = new byte[2048];
//			   int c;
//			   while ((c = bis.read(bytes)) != -1) {
//			    bos.write(bytes);
//			   }
//			      //将缓冲区中的数据全部写出
//			   bos.flush();
//			   //关闭流
//			   bis.close();
//			   bos.close();
//		}catch(Exception ex){
//			ex.printStackTrace();
//		}
//	}
}
